using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Linq;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Security;

using SPaDevToolkit.Diagnostics;

using Northwind.ServiceObjects;
using Northwind.Common.Diagnostics;

using Microsoft.Practices.SharePoint.Common.Logging;

namespace Northwind.ServiceApplication
{
    /// <summary>
    /// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.
    /// </summary>
    /// <remarks>
    /// The GUID attached to this class may be used during packaging and should not be modified.
    /// </remarks>

    [Guid("8d43f398-9ca7-4676-ab6d-459eb2bed9da")]
    public class NorthwindServiceEventReceiver : SPFeatureReceiver
    {

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            try
            {
                AddDiagnosticAreas();

                SPWebService adminService = (SPWebService)properties.Feature.Parent;
                NorthwindServiceFactory serviceFactory = new NorthwindServiceFactory(adminService);
                SPFarm farm = adminService.Farm;

                NorthwindService service = farm.Services.GetValue<NorthwindService>();
                if (service == null)
                {
                    try
                    {
                        service = serviceFactory.CreateService();
                    }
                    catch (Exception ex)
                    {
                        Logger.WriteException(ex, "Error creating Northwind Service", 0, EventSeverity.Error, AreaNames.Northwind, CategoryNames.Service);
                        serviceFactory.RemoveObject(service, false);
                        throw;
                    }
                }
                NorthwindServiceProxy serviceProxy = farm.ServiceProxies.GetValue<NorthwindServiceProxy>();
                if (serviceProxy == null)
                {
                    try
                    {
                        serviceProxy = serviceFactory.CreateServiceProxy(NorthwindServiceProxy.DefaultName);
                    }
                    catch (Exception ex)
                    {
                        Logger.WriteException(ex, string.Format("Error creating {0}", NorthwindServiceProxy.DefaultName), 0, EventSeverity.Error, AreaNames.Northwind, CategoryNames.Service);
                        serviceFactory.RemoveObject(serviceProxy, false);
                        serviceFactory.RemoveObject(service, false);
                        throw;
                    }
                }

                bool errorCreatingInstances = false;
                foreach (SPServer server in farm.Servers.Where(s => s.Role != SPServerRole.Invalid))
                {
                    NorthwindServiceInstance serviceInstance = null;
                    try
                    {
                        serviceInstance = serviceFactory.CreateServiceInstance(NorthwindServiceInstance.DefaultName, server, service);
                        serviceInstance.Update();
                        //Can only provision (start) instance on current machine. If you try, and exception is raised
                        if (SPServer.Local.Id == server.Id)
                            serviceInstance.Provision();
                    }
                    catch (Exception ex)
                    {
                        errorCreatingInstances = true;
                        Logger.WriteException(ex, string.Format("Error creating {0} Instance on {1}", NorthwindServiceInstance.DefaultName, server.Name), 0, EventSeverity.Error, AreaNames.Northwind, CategoryNames.Service);
                    }
                }
                if (errorCreatingInstances)
                {
                    serviceFactory.RemoveServiceInstances(service, false);
                    serviceFactory.RemoveObject(serviceProxy, false);
                    serviceFactory.RemoveObject(service, false);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteException(ex, "Error installing Northwind Service", 0, EventSeverity.Error, AreaNames.Northwind, CategoryNames.Service);
                throw;
            }
        }


        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            try
            {
                SPWebService adminService = (SPWebService)properties.Feature.Parent;
                NorthwindServiceFactory serviceFactory = new NorthwindServiceFactory(adminService);
                serviceFactory.RemoveServiceAndAllDependentObjects();
            }
            catch (Exception ex)
            {
                throw new Exception("An error deactivating the feature. See the server log for details");
            }
        }

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
            try
            {
                SPWebService adminService = (SPWebService)properties.Feature.Parent;
                NorthwindServiceFactory serviceFactory = new NorthwindServiceFactory(adminService);
                serviceFactory.RemoveServiceAndAllDependentObjects();
                
                RemoveDiagnosticAreas();
            }
            catch (Exception ex)
            {
                throw new Exception("An error uninstalling the feature. See the server log for details");
            }
        }

        private void AddDiagnosticAreas()
        {
            try
            {
                AreaManager.AddCategory(AreaNames.Northwind, CategoryNames.Service, true);
                DiagnosticsAreaEventSource.EnsureConfiguredAreasRegistered();
            }
            catch (Exception)
            {
            }
        }

        private void RemoveDiagnosticAreas()
        {
            try
            {
                AreaManager.RemoveArea(AreaNames.Northwind);
            }
            catch (Exception)
            {
            }
        }
    }
}
